package admin

import (
	"encoding/json"
	"errors"
	"exercise/application/yiran/app"
	"exercise/application/yiran/app/libs"
	"exercise/application/yiran/app/model"
	"exercise/application/yiran/app/request/adminRequest"
	"fmt"
	"github.com/LindsayBradford/go-dbf/godbf"
	"github.com/gin-gonic/gin"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
)

type dbfService struct{}

// RecognizeDbf 解压zip文件夹
func (d *dbfService) RecognizeDbf(ctx *gin.Context, request *adminRequest.RecognizeDbfRequest) (ret interface{}, err error) {
	schoolId, _ := ctx.Get("schoolId")
	file := new(model.FileCenter)
	_ = model.NewDb("").FindOne(file, "id = ?", []interface{}{request.SourceId}, "*", nil)

	//1.检测zip文件是否存在
	if file.SavePath == "" || libs.FileIsNotExist(filepath.Join(app.YiRanPublicDir, file.SavePath)) == true {
		return ret, errors.New("zip文件不存在")
	}

	//2.解压zip文件
	dest := filepath.Join(app.YiRanPublicDir, "dbf/"+libs.Int64String(schoolId.(int64))+"/"+strconv.Itoa(request.Year)+"/"+strconv.Itoa(request.SourceId))
	err = libs.UnzipFile(filepath.Join(app.YiRanPublicDir, file.SavePath), dest, false)

	//3.获取一级文件夹名称
	folderList, err := libs.GetFolderName(dest, 1)
	if err != nil {
		return ret, errors.New(err.Error())
	}

	//4.文件夹省份校验
	validProvince, invalidProvince, err := d.checkProvinceValid(folderList, dest)

	//5.写入正确省份的配置文件
	d.writesProvinceSys(validProvince, dest)

	return map[string]interface{}{
		"validProvince":   validProvince,
		"invalidProvince": invalidProvince,
	}, nil
}

// checkProvinceValid 省份校验
func (d *dbfService) checkProvinceValid(folderList []string, dest string) (validProvince []string, invalidProvince []string, err error) {
	//获取省份文件
	provinceList := d.GetAllProvince()
	//有效省份
	validProvince = make([]string, 0)
	//无效省份
	invalidProvince = make([]string, 0)

	for _, file := range folderList {
		pro := strings.Replace(file, dest+libs.GetSeparator(), "", -1)
		_, ok := provinceList[pro]
		if ok {
			validProvince = append(validProvince, pro)
		} else {
			invalidProvince = append(invalidProvince, pro)
		}
	}

	return
}

// writesProvinceSys 写入省份配置文件,统一省份名称
func (d *dbfService) writesProvinceSys(validProvince []string, dest string) bool {
	if validProvince != nil {
		//获取省份文件
		provinceList := d.GetAllProvince()
		for _, pro := range validProvince {
			val, ok := provinceList[pro]
			if ok {
				sys := strings.Split(val, "/")
				data := make(map[string]string, 0)
				data["province"] = sys[0]
				data["ver_name"] = sys[2]
				data["ignore"] = "n" //是否忽略
				//写入文件

				libs.WritesAnyToFile(filepath.Join(dest, pro, "sys.json"), data)
			}
		}
		return true
	}
	return false
}

// GetAllProvince 获取配置文件中的省份数据
func (d *dbfService) GetAllProvince() (provinceList map[string]string) {
	province, _ := libs.ReadFile(filepath.Join(app.YiRanPublicDir, "all_province.json"))
	provinceList = make(map[string]string, 0)
	json.Unmarshal(province, &provinceList)
	return provinceList
}

// CorrectionProvince 省份纠正
func (d *dbfService) CorrectionProvince(ctx *gin.Context, request *adminRequest.CorrectionProvinceRequest) (err error) {
	schoolId, _ := ctx.Get("schoolId")
	//根目录
	dest := filepath.Join(app.YiRanPublicDir, "dbf/"+libs.Int64String(schoolId.(int64))+"/"+strconv.Itoa(request.Year)+"/"+strconv.Itoa(request.SourceId))

	for _, val := range request.Content {
		data := make(map[string]string, 0)
		data["province"] = val["province"]
		data["ver_name"] = "26"
		data["ignore"] = val["ignore"] //是否忽略
		//写入文件
		libs.WritesAnyToFile(filepath.Join(dest, val["title"], "sys.json"), data)
	}
	return nil
}

// MovingProvinceClamp 省份文件夹上移
func (d *dbfService) MovingProvinceClamp(ctx *gin.Context, request *adminRequest.MovingProvinceClampRequest) (err error) {
	schoolId, _ := ctx.Get("schoolId")
	src := filepath.Join(app.YiRanPublicDir, "dbf/"+libs.Int64String(schoolId.(int64))+"/"+strconv.Itoa(request.Year)+"/"+strconv.Itoa(request.SourceId))
	destTmp := filepath.Join(app.YiRanPublicDir, "dbf/"+libs.Int64String(schoolId.(int64))+"/"+strconv.Itoa(request.Year)+"/"+strconv.Itoa(request.SourceId)+"_tmp")
	//1.获取dest下的全部一级文件
	fileList, err := libs.GetFolderName(src, 1)
	//2.文件夹移动
	for _, f := range fileList {
		err = libs.MoveFolder(f, destTmp)
	}
	//3.删除资源目录
	os.Remove(src)
	//修改文件名
	err = os.Rename(destTmp, src)

	return err
}

// ReadDbf 读取dbf文件
func (d *dbfService) ReadDbf(ctx *gin.Context, request *adminRequest.ReadDbfRequest) (ret interface{}, err error) {

	schoolId, _ := ctx.Get("schoolId")
	dest := libs.GetPathToSlash([]string{
		app.YiRanPublicDir,
		"dbf",
		libs.Int64String(schoolId.(int64)),
		strconv.Itoa(request.Year),
		strconv.Itoa(request.SourceId),
	})
	//
	//r, err := libs.ReadFile(libs.GetUnifiedPath(dest + "/广东_艺体类.json"))
	//
	//if err != nil {
	//	return nil, err
	//}
	//
	//s := make([]map[string]interface{}, 0)
	//
	//err = libs.JsonDecode(r, &s)
	//if err != nil {
	//	return nil, err
	//}
	//
	//return s, nil

	//1.读取所有的子文件名称,该文件下一定存在tdd.dbf文件
	fileList, err := libs.GetFolderName(dest, 2)
	for _, f := range fileList {
		f = libs.GetUnifiedPath(f)
		//1.获取主文件信息
		mainFilename := d.GetMainFilename(f, "T_BMK.DBF")
		list, err := d.GetMainInfo(filepath.Join(f, mainFilename))
		if err != nil {
			continue
		}
		//2.关联DM数据表内容
		dmList, err := d.GetDMFileData(f)
		if err != nil {
			continue
		}
		//3.关联其他表数据
		linkData, err := d.GetLinkFileData(f, mainFilename)
		linkData["school_id"] = schoolId
		linkData["year"] = request.Year
		//4.组装数据
		studentList := make([]map[string]interface{}, 0)
		//5.如果是新版数据,将T_TDD与BMK合并
		for _, value := range list {
			//新高考合并bmk与tdd表
			if mainFilename == "T_BMK.DBF" {
				d.mergeUserInfo(value, linkData)
			}
			stu, _ := d.AssemblyStudentData(value, dmList, linkData, mainFilename)
			studentList = append(studentList, stu)
		}

		//6.写入到txt文件中
		sysFilename := strings.Replace(strings.Replace(f, dest+"/", "", -1), "/", "_", -1)
		err = libs.WritesAnyToFile(libs.GetPathToSlash([]string{
			dest,
			sysFilename + ".json",
		}), studentList)
	}

	return map[string]interface{}{
		"fileList": fileList,
		"dest":     dest,
	}, nil
}

// GetMainFilename 获取主文件名
func (d *dbfService) GetMainFilename(path, filename string) string {
	var mainFilename string
	b := libs.FileIsNotExist(filepath.Join(path, filename))
	if b { //BMK存在表示是新版
		mainFilename = "T_TDD.DBF"
	} else {
		mainFilename = "T_BMK.DBF"
	}
	return mainFilename
}

// GetMainInfo 获取主表内容
func (d *dbfService) GetMainInfo(path string) (list []map[string]string, err error) {
	list = make([]map[string]string, 0)
	table, err := godbf.NewFromFile(path, "GBK")
	if err != nil {
		return nil, fmt.Errorf("读取dbf文件失败：%w", err)
	}
	//1.获取所有字段
	fieldsName := table.FieldNames()
	//2.获取dbf中记录的数量
	for i := 0; i < table.NumberOfRecords(); i++ {
		item := make(map[string]string, 0)
		for _, field := range fieldsName {
			val, err := table.FieldValueByName(i, field)
			if err != nil {
				return nil, fmt.Errorf("读取dbf中记录失败：%w", err)
			}
			item[field] = val
		}
		list = append(list, item)
	}
	return list, nil
}

// GetDMFileData 获取DM.DBF文件中的数据
func (d *dbfService) GetDMFileData(path string) (list map[string]string, err error) {
	list = make(map[string]string, 0)
	err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.Contains(path, "DM.DBF") { // 排除初始目录及其子目录"an hui"
			fileName := info.Name()
			//1.当前文件名
			table, err := godbf.NewFromFile(path, "GBK")
			if err != nil {
				return fmt.Errorf("读取dbf文件失败：%w", err)
			}
			//2.获取所有字段
			tmpK := strings.Replace(strings.Replace(fileName, ".DBF", "", -1), "TD_", "", -1)
			//3.获取表中的所有记录
			for i := 0; i < table.NumberOfRecords(); i++ {
				//获取每条记录的内容
				rowData := table.GetRowAsSlice(i)
				key := tmpK + "_" + rowData[0]
				list[key] = rowData[1]
			}
		}
		return nil
	})
	return list, err
}

// GetLinkFileData 获取关联表数据 表名为数据库名 关联字段为key 一行记录为数据
func (d *dbfService) GetLinkFileData(path string, mainFilename string) (linkFileDataList map[string]interface{}, err error) {
	linkFileMap := make(map[string][]string, 0)
	linkFileMap["T_JHK.DBF"] = []string{"PCDM", "KLDM", "TDDW", "ZYDH"}
	linkFileMap["T_KSJL.DBF"] = []string{"KSH"}
	linkFileMap["T_LQZY.DBF"] = []string{"KSH"}
	linkFileMap["T_QBJHK.DBF"] = []string{"PCDM", "KLDM", "TDDW", "ZYDH"}
	linkFileMap["T_TDDW.DBF"] = []string{"PCDM", "KLDM", "TDDWDM"}
	linkFileMap["T_TJXX.DBF"] = []string{"KSH"}

	if mainFilename == "T_BMK.DBF" { //新版高考数据
		linkFileMap["T_TDD.DBF"] = []string{"KSH"}
		linkFileMap["T_KSXKCJ.DBF"] = []string{"KSH"}
	} else {
		linkFileMap["T_KSHKCJ.DBF"] = []string{"KSH"}
	}

	//1.全部文件的数据总计
	linkFileDataList = make(map[string]interface{}, 0)

	for filename, fields := range linkFileMap {
		table, err := godbf.NewFromFile(filepath.Join(path, filename), "GBK")
		if err != nil {
			return nil, fmt.Errorf("文件打开失败：%w", err)
		}
		fieldsName := table.FieldNames()

		//1.filename文件中的全部记录数，一张表里相同标识的数据使用[]map[string]string的方式放到一起
		list := make(map[string][]map[string]string, 0)
		for i := 0; i < table.NumberOfRecords(); i++ {
			//1.获取每一条数据
			item := make(map[string]string, 0)
			for _, field := range fieldsName {
				val, _ := table.FieldValueByName(i, field)
				item[field] = val
			}
			//2.每条数据存放到map中的key值
			indexKey := make([]string, 0)
			for _, kField := range fields {
				indexKey = append(indexKey, item[kField])
			}

			//3.相同的indexKey的数据放到一起
			list[strings.Join(indexKey, "_")] = append(list[strings.Join(indexKey, "_")], item)
		}
		//组装最终的数据
		linkFileDataList[filename] = list

	}
	return
}

// mergeUserInfo 合并用户信息
func (d *dbfService) mergeUserInfo(value map[string]string, linkData map[string]interface{}) {
	tdd := linkData["T_TDD.DBF"].(map[string][]map[string]string)
	tddUser := tdd[value["KSH"]][0]

	for k, v := range tddUser {
		value[k] = v
	}
}

// AssemblyStudentData 组装数据
func (d *dbfService) AssemblyStudentData(value map[string]string, dmData map[string]string, linkData map[string]interface{}, mainFilename string) (student map[string]interface{}, err error) {
	dbfStudent := new(model.DbfStudent)
	//1.获取dbfStudent的属性
	dbfStudentType := reflect.TypeOf(dbfStudent).Elem()
	student = make(map[string]interface{}, 0)
	for i := 0; i < dbfStudentType.NumField(); i++ {
		//1.字段名
		gorm := dbfStudentType.Field(i).Tag.Get("gorm")
		//2.关联dm表中的信息
		dm := dbfStudentType.Field(i).Tag.Get("dm")
		//3.默认值
		defaultVal := dbfStudentType.Field(i).Tag.Get("default")
		//4.方法处理
		method := dbfStudentType.Field(i).Tag.Get("method")
		//映射value数据与DbfStudent之间的映射关系
		if gorm != "" {
			//获取dbfStudent的属性名
			field := dbfStudentType.Field(i).Name
			//获取全的数据
			student[gorm] = value[strings.ToUpper(field)]

			if defaultVal != "" {
				student[gorm] = defaultVal
				continue
			}

			//通过DM获取DM.DBF里的数据
			if dm != "" {
				if value[dm] != "" {
					key := dm + "_" + value[dm]
					student[gorm] = dmData[key]
				}
				continue
			}

			//关联其他
			if method != "" {
				switch gorm {
				case "ksjl", "tjxx": //考生简历,体检信息
					student[gorm] = string(libs.JsonEncode(d.GetStudentXx(value, linkData, gorm)))
				case "province", "city": //省市
					student[gorm] = d.GetProvinceOrCity(value, gorm)
				case "xzdm": //学制代码
					student[gorm] = d.GetJhk(value, linkData)
				case "xzmc", "level": //学制名称,层级
					student[gorm] = d.GetXzmcOrLevel(value, gorm)
				case "zymc1", "zymc2", "zymc3", "zymc4", "zymc5", "zymc6": //专业名称
					val, index := d.GetZymc(value, linkData, gorm)
					student["zymc"+index] = val
				case "lqzydm", "lqzydh", "lqzymc": //专业代码,专业代号,专业名称
					val, index := d.GetLqzy(value, linkData, gorm)
					student["lqzy"+strings.ToLower(index)] = val
				case "tddwmc": //投档单位名称
					student[gorm] = d.GetTddwmc(value, linkData)
				case "sftj", "blqzy":
					student[gorm] = d.GetSftj(value, gorm)
				}
				continue
			}
		}
	}

	return
}

// GetStudentXx 处理学生信息
func (d *dbfService) GetStudentXx(value map[string]string, linkData map[string]interface{}, gorm string) (ret interface{}) {
	f := "T_" + strings.ToUpper(gorm) + ".DBF"
	if linkData[f] == nil {
		return nil
	}

	linkList := linkData[f].(map[string][]map[string]string)
	if linkList != nil {
		return linkList[value["KSH"]]
	}
	return nil
}

// GetProvinceOrCity 处理省市
func (d *dbfService) GetProvinceOrCity(value map[string]string, gorm string) string {
	if gorm == "province" {
		return value["KSH"][2:4] + "0000"
	}
	return value["KSH"][2:6] + "00"
}

// GetJhk 处理学制相关类数据
func (d *dbfService) GetJhk(value map[string]string, linkData map[string]interface{}) (val interface{}) {
	if linkData["T_JHK.DBF"] == nil {
		return val
	}
	jhk := linkData["T_JHK.DBF"].(map[string][]map[string]string)

	k := value["PCDM"] + "_" + value["KLDM"] + "_" + value["TDDW"] + "_" + value["LQZY"]

	if len(jhk[k]) != 0 {
		val = jhk[k][0]["XZNX"]
	}
	return
}

// GetXzmcOrLevel 通过学制dm获取层级和学制名称
func (d *dbfService) GetXzmcOrLevel(value map[string]string, gorm string) interface{} {

	var val interface{}
	if gorm == "xzmc" {
		val = "四年"
		if value["xzdm"] == "3" {
			val = "三年"
		}
	} else if gorm == "level" {
		val = 1
		if value["xzdm"] == "3" {
			val = 2
		}
	}
	return val
}

// GetZymc 处理专业名称
func (d *dbfService) GetZymc(value map[string]string, linkData map[string]interface{}, gorm string) (val string, index string) {
	if linkData["T_QBJHK.DBF"] == nil {
		return
	}
	index = gorm[len(gorm)-1:]
	zymc := linkData["T_QBJHK.DBF"].(map[string][]map[string]string)
	k := value["PCDM"] + "_" + value["KLDM"] + "_" + value["TDDW"] + "_" + value["ZYDH"+index]
	if len(zymc[k]) != 0 {
		val = zymc[k][0]["ZYMC"]
	}
	return
}

// GetLqzy 录取专业信息
func (d *dbfService) GetLqzy(value map[string]string, linkData map[string]interface{}, gorm string) (val string, index string) {
	//判断新版本或者老版本
	if linkData["T_TDD.DBF"] == nil { //老版本
		if linkData["T_QBJHK.DBF"] == nil {
			return
		}
		index = gorm[len(gorm)-2:]
		qbjhk := linkData["T_QBJHK.DBF"].(map[string][]map[string]string)
		k := value["PCDM"] + "_" + value["KLDM"] + "_" + value["TDDW"] + "_" + value["LQZY"]
		if len(qbjhk[k]) != 0 {
			val = qbjhk[k][0]["ZY"+strings.ToUpper(index)]
		}
	} else { //新版

	}
	return
}

// GetTddwmc 投档单位名称
func (d *dbfService) GetTddwmc(value map[string]string, linkData map[string]interface{}) (val string) {
	if linkData["T_TDDW.DBF"] == nil {
		return
	}
	var k string
	tddw := linkData["T_TDDW.DBF"].(map[string][]map[string]string)
	if linkData["T_TDD.DBF"] == nil { //老版本
		k = value["TDDW"]
	} else { //新版
		if tdd := linkData["T_TDD.DBF"].(map[string][]map[string]string); tdd[value["KSH"]] != nil {
			k = tdd[value["KSH"]][0]["TDDWDM"]
		}
	}
	if len(tddw[k]) != 0 {
		val = tddw[k][0]["TDDWMC"]
	}
	return
}

// GetSftj 是否调剂
func (d *dbfService) GetSftj(value map[string]string, gorm string) (val string) {
	//1.lqzy不在zydh1 ~ zydh6中 就是调剂
	//2.被录取专业blqzy 就是后面的数字
	list := make(map[string]string)
	list[value["ZYDH1"]] = "1"
	list[value["ZYDH2"]] = "2"
	list[value["ZYDH3"]] = "3"
	list[value["ZYDH4"]] = "4"
	list[value["ZYDH5"]] = "5"
	list[value["ZYDH6"]] = "6"
	i, ok := list[value["LQZY"]]
	if gorm == "sftj" {
		val = "否"
		if !ok {
			val = "是"
		}
	} else {
		val = "0"
		if ok {
			val = i
		}
	}
	return
}

func NewDbfService() *dbfService {
	return &dbfService{}
}
